{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Part 9 - 加密程序简介\n",
    "\n",
    "信不信由你，有可能使用加密数据进行计算。换句话说，可以在程序中对所有变量进行加密的情况下运行该程序！\n",
    "\n",
    "在本教程中，我们将逐步介绍加密计算的基本工具。特别地，我们将集中于一种流行的方法，称为安全多方计算。在本课程中，我们将学习如何构建一个可以对加密数字执行计算的加密计算器。\n",
    "\n",
    "\n",
    "\n",
    "作者:\n",
    "- Andrew Trask - Twitter: [@iamtrask](https://twitter.com/iamtrask)\n",
    "- Théo Ryffel - GitHub: [@LaRiffle](https://github.com/LaRiffle)\n",
    "\n",
    "参考文献: \n",
    "- Morten Dahl - [Blog](https://mortendahl.github.io) - Twitter: [@mortendahlcs](https://twitter.com/mortendahlcs)\n",
    "\n",
    "中文版译者：\n",
    "- Hou Wei - github：[@dljgs1](https://github.com/dljgs1)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 第1步: 使用安全的多方计算进行加密\n",
    "\n",
    "乍一看，SMPC（Secure Multi-Party Computation，安全多方计算）是一种非常奇怪的“加密”形式。 每个值都被分成多个“共享”，而不是使用公共/私有密钥对变量进行加密，每个共享都像私有密钥一样工作。 通常，这些“份额”将分配给2个或更多_owners_。 因此，为了解密变量，所有所有者必须同意允许解密。 本质上，每个人都有一个私钥。\n",
    "\n",
    "### Encrypt()\n",
    "\n",
    "因此，假设我们要“加密”变量“x”，可以通过以下方式进行。\n",
    "\n",
    " > 加密不使用浮点数或实数，而是在称为[整数商环](http://mathworld.wolfram.com/QuotientRing.html)的数学空间中进行，该空间基本上是介于`0`和`Q-1`之间的整数 ，其中`Q`是质数，并且“足够大”，以便该空间可以包含我们在实验中使用的所有数字。 实际上，给定值`x`整数，我们将`x％Q`放入环中。 （这就是为什么我们避免使用数字“ x”> Q”的原因）。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "Q = 1234567891011"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "x = 25"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "import random\n",
    "\n",
    "def encrypt(x):\n",
    "    share_a = random.randint(-Q,Q)\n",
    "    share_b = random.randint(-Q,Q)\n",
    "    share_c = (x - share_a - share_b) % Q\n",
    "    return (share_a, share_b,  share_c)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(890804432397, -2305631655, 346069090294)"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "encrypt(x)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "如您所见，我们将变量`x`分为3个不同的份额，可以将其发送给3个不同的所有者。\n",
    "\n",
    "### Decrypt()\n",
    "\n",
    "如果我们想解密这3个份额，我们可以简单地将它们加在一起并取结果的模数（模Q）。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "def decrypt(*shares):\n",
    "    return sum(shares) % Q"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [],
   "source": [
    "a,b,c = encrypt(25)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "25"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "decrypt(a, b, c)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "重要的是，请注意，如果我们尝试仅使用两个共享进行解密，则解密将不起作用！"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "778460474681"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "decrypt(a, b)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "因此，我们需要所有所有者参与才能解密该值。 通过这种方式，`shares`就像私钥一样，所有私钥都必须存在才能解密值。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 第2步: 使用SMPC的基本算法\n",
    "\n",
    "然而，安全多方计算的真正非凡特性是能够在变量**被加密的同时进行计算**。让我们在下面演示简单的加法。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [],
   "source": [
    "x = encrypt(25)\n",
    "y = encrypt(5)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [],
   "source": [
    "def add(x, y):\n",
    "    z = list()\n",
    "    # 第一个工作机将其共享分片相加\n",
    "    z.append((x[0] + y[0]) % Q)\n",
    "    \n",
    "    # 第二个工作机将其共享分片相加\n",
    "    z.append((x[1] + y[1]) % Q)\n",
    "    \n",
    "    # 第三个工作机将其共享分片相加\n",
    "    z.append((x[2] + y[2]) % Q)\n",
    "    \n",
    "    return z"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "30"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "decrypt(*add(x,y))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 成功！！！\n",
    "\n",
    "您做到了！如果每个工作机（分别）将其份额加在一起，则所得份额将解密为正确的值（25 + 5 == 30）。\n",
    "\n",
    "事实证明，存在SMPC协议，该协议可以允许针对以下操作进行此加密计算：\n",
    "- 加法（我们刚刚看到）\n",
    "- 乘法\n",
    "- 比较\n",
    "\n",
    "并使用这些基本的基础原语，我们可以执行任意计算！！！\n",
    "\n",
    "在下一节中，我们将学习如何使用PySyft库执行这些操作！"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 第3步: 使用PySyft的SMPC\n",
    "\n",
    "在前面的部分中，我们概述了关于SMPC应该起作用的一些基本直觉。但是，实际上，在编写加密程序时，我们不需要自己亲自编写所有原始操作。因此，在本节中，我们将逐步介绍如何使用PySyft进行加密计算的基础知识。特别是，我们将集中精力于如何执行前面提到的3个原语：加法，乘法和比较。\n",
    "\n",
    "首先，我们需要创建一些虚拟工作机（希望您现在对我们之前的教程已经很熟悉了）。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [],
   "source": [
    "import torch\n",
    "import syft as sy\n",
    "hook = sy.TorchHook(torch)\n",
    "\n",
    "bob = sy.VirtualWorker(hook, id=\"bob\")\n",
    "alice = sy.VirtualWorker(hook, id=\"alice\")\n",
    "bill = sy.VirtualWorker(hook, id=\"bill\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 基础的加/解密\n",
    "\n",
    "加密就像获取任何PySyft张量并调用.share()一样简单。解密就像在共享变量上调用.get()一样简单"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [],
   "source": [
    "x = torch.tensor([25])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "tensor([25])"
      ]
     },
     "execution_count": 14,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "x"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [],
   "source": [
    "encrypted_x = x.share(bob, alice, bill)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "tensor([25])"
      ]
     },
     "execution_count": 16,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "encrypted_x.get()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 内省加密值\n",
    "\n",
    "如果我们仔细观察Bob，Alice和Bill的工作机，我们可以看到创建的份额！"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{}"
      ]
     },
     "execution_count": 17,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "bob._objects"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [],
   "source": [
    "x = torch.tensor([25]).share(bob, alice, bill)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "tensor([3212861001891376707])"
      ]
     },
     "execution_count": 19,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# Bob's share\n",
    "bobs_share = list(bob._objects.values())[0]\n",
    "bobs_share"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "tensor([61371170032936135])"
      ]
     },
     "execution_count": 20,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# Alice's share\n",
    "alices_share = list(alice._objects.values())[0]\n",
    "alices_share"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "tensor([1337453846503075087])"
      ]
     },
     "execution_count": 21,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# Bill's share\n",
    "bills_share = list(bill._objects.values())[0]\n",
    "bills_share"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "如果愿意，我们可以使用我们之前讨论的**同样**的方法解密这些值！！！"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "tensor([25])"
      ]
     },
     "execution_count": 22,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "Q = x.child.field\n",
    "\n",
    "(bobs_share + alices_share + bills_share) % Q"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "如您所见，当我们调用`.share()`时，它只是将值分割成3股，并向每一方发送了一份！"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 加密加法\n",
    "\n",
    "现在您看到我们可以对基础值执行加法了！API的构造使我们可以像执行普通的PyTorch张量那样简单地执行算法。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {},
   "outputs": [],
   "source": [
    "x = torch.tensor([25]).share(bob,alice)\n",
    "y = torch.tensor([5]).share(bob,alice)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "tensor([30])"
      ]
     },
     "execution_count": 24,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "z = x + y\n",
    "z.get()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "tensor([20])"
      ]
     },
     "execution_count": 25,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "z = x - y\n",
    "z.get()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 加密乘法\n",
    "\n",
    "为了进行乘法运算，我们需要一个额外的一方负责连续生成随机数（而不与其他任何一方串通）。 我们称此人为“密码提供者”。 对于所有密集用途，加密提供者只是一个额外的VirtualWorker，但必须承认加密提供者不是“所有者”，因为他/她不拥有股份，而是需要信任才能避免串通的人与任何现有股东。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {},
   "outputs": [],
   "source": [
    "crypto_provider = sy.VirtualWorker(hook, id=\"crypto_provider\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {},
   "outputs": [],
   "source": [
    "x = torch.tensor([25]).share(bob,alice, crypto_provider=crypto_provider)\n",
    "y = torch.tensor([5]).share(bob,alice, crypto_provider=crypto_provider)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "tensor([125])"
      ]
     },
     "execution_count": 28,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# multiplication\n",
    "\n",
    "z = x * y\n",
    "z.get()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "而且可以执行矩阵乘法"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "metadata": {},
   "outputs": [],
   "source": [
    "x = torch.tensor([[1, 2],[3,4]]).share(bob,alice, crypto_provider=crypto_provider)\n",
    "y = torch.tensor([[2, 0],[0,2]]).share(bob,alice, crypto_provider=crypto_provider)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "tensor([[2, 4],\n",
       "        [6, 8]])"
      ]
     },
     "execution_count": 30,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# matrix multiplication\n",
    "\n",
    "z = x.mm(y)\n",
    "z.get()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 加密比较\n",
    "私有值之间的私有比较也是可能的。 我们在这里依赖SecureNN协议，其详细信息可以在[这里](https://eprint.iacr.org/2018/442.pdf)找到。比较的结果也是私有共享张量。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "metadata": {},
   "outputs": [],
   "source": [
    "x = torch.tensor([25]).share(bob,alice, crypto_provider=crypto_provider)\n",
    "y = torch.tensor([5]).share(bob,alice, crypto_provider=crypto_provider)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "tensor([1])"
      ]
     },
     "execution_count": 32,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "z = x > y\n",
    "z.get()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "tensor([0])"
      ]
     },
     "execution_count": 33,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "z = x <= y\n",
    "z.get()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "tensor([0])"
      ]
     },
     "execution_count": 34,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "z = x == y\n",
    "z.get()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 35,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "tensor([1])"
      ]
     },
     "execution_count": 35,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "z = x == y + 20\n",
    "z.get()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "您还可以执行求最值操作"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 36,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "tensor([4])"
      ]
     },
     "execution_count": 36,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "x = torch.tensor([2, 3, 4, 1]).share(bob,alice, crypto_provider=crypto_provider)\n",
    "x.max().get()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 37,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "tensor([4, 3])"
      ]
     },
     "execution_count": 37,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "x = torch.tensor([[2, 3], [4, 1]]).share(bob,alice, crypto_provider=crypto_provider)\n",
    "max_values, max_ids = x.max(dim=0)\n",
    "max_values.get()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 恭喜!!! 是时候加入社区了!\n",
    "\n",
    "祝贺您完成本笔记本教程！ 如果您喜欢此方法，并希望加入保护隐私、去中心化AI和AI供应链（数据）所有权的运动，则可以通过以下方式做到这一点！\n",
    "\n",
    "### 给 PySyft 加星\n",
    "\n",
    "帮助我们的社区的最简单方法是仅通过给GitHub存储库加注星标！ 这有助于提高人们对我们正在构建的出色工具的认识。\n",
    "\n",
    "- [Star PySyft](https://github.com/OpenMined/PySyft)\n",
    "\n",
    "\n",
    "### 加入我们的 Slack!\n",
    "\n",
    "保持最新进展的最佳方法是加入我们的社区！ 您可以通过填写以下表格来做到这一点[http://slack.openmined.org](http://slack.openmined.org)\n",
    "\n",
    "### 加入代码项目!\n",
    "\n",
    "对我们的社区做出贡献的最好方法是成为代码贡献者！ 您随时可以转到PySyft GitHub的Issue页面并过滤“projects”。这将向您显示所有概述，选择您可以加入的项目！如果您不想加入项目，但是想做一些编码，则还可以通过搜索标记为“good first issue”的GitHub问题来寻找更多的“一次性”微型项目。\n",
    "\n",
    "- [PySyft Projects](https://github.com/OpenMined/PySyft/issues?q=is%3Aopen+is%3Aissue+label%3AProject)\n",
    "- [Good First Issue Tickets](https://github.com/OpenMined/PySyft/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22)\n",
    "\n",
    "### 捐赠\n",
    "\n",
    "如果您没有时间为我们的代码库做贡献，但仍想提供支持，那么您也可以成为Open Collective的支持者。所有捐款都将用于我们的网络托管和其他社区支出，例如黑客马拉松和聚会！\n",
    "\n",
    "[OpenMined's Open Collective Page](https://opencollective.com/openmined)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.4"
  },
  "latex_envs": {
   "LaTeX_envs_menu_present": true,
   "autoclose": false,
   "autocomplete": true,
   "bibliofile": "biblio.bib",
   "cite_by": "apalike",
   "current_citInitial": 1,
   "eqLabelWithNumbers": true,
   "eqNumInitial": 1,
   "hotkeys": {
    "equation": "Ctrl-E",
    "itemize": "Ctrl-I"
   },
   "labels_anchors": false,
   "latex_user_defs": false,
   "report_style_numbering": false,
   "user_envs_cfg": false
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
